home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2000 March / maximum-cd-2000-03.iso / Quake3 Game Source / Q3AGameSource.exe / Main / bg_slidemove.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-18  |  7.9 KB  |  304 lines

  1. // Copyright (C) 1999-2000 Id Software, Inc.
  2. //
  3. // bg_slidemove.c -- part of bg_pmove functionality
  4.  
  5. #include "q_shared.h"
  6. #include "bg_public.h"
  7. #include "bg_local.h"
  8.  
  9. /*
  10.  
  11. input: origin, velocity, bounds, groundPlane, trace function
  12.  
  13. output: origin, velocity, impacts, stairup boolean
  14.  
  15. */
  16.  
  17. /*
  18. ==================
  19. PM_SlideMove
  20.  
  21. Returns qtrue if the velocity was clipped in some way
  22. ==================
  23. */
  24. #define    MAX_CLIP_PLANES    5
  25. qboolean    PM_SlideMove( qboolean gravity ) {
  26.     int            bumpcount, numbumps;
  27.     vec3_t        dir;
  28.     float        d;
  29.     int            numplanes;
  30.     vec3_t        planes[MAX_CLIP_PLANES];
  31.     vec3_t        primal_velocity;
  32.     vec3_t        clipVelocity;
  33.     int            i, j, k;
  34.     trace_t    trace;
  35.     vec3_t        end;
  36.     float        time_left;
  37.     float        into;
  38.     vec3_t        endVelocity;
  39.     vec3_t        endClipVelocity;
  40.     
  41.     numbumps = 4;
  42.  
  43.     VectorCopy (pm->ps->velocity, primal_velocity);
  44.  
  45.     if ( gravity ) {
  46.         VectorCopy( pm->ps->velocity, endVelocity );
  47.         endVelocity[2] -= pm->ps->gravity * pml.frametime;
  48.         pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5;
  49.         primal_velocity[2] = endVelocity[2];
  50.         if ( pml.groundPlane ) {
  51.             // slide along the ground plane
  52.             PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, 
  53.                 pm->ps->velocity, OVERCLIP );
  54.         }
  55.     }
  56.  
  57.     time_left = pml.frametime;
  58.  
  59.     // never turn against the ground plane
  60.     if ( pml.groundPlane ) {
  61.         numplanes = 1;
  62.         VectorCopy( pml.groundTrace.plane.normal, planes[0] );
  63.     } else {
  64.         numplanes = 0;
  65.     }
  66.  
  67.     // never turn against original velocity
  68.     VectorNormalize2( pm->ps->velocity, planes[numplanes] );
  69.     numplanes++;
  70.  
  71.     for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) {
  72.  
  73.         // calculate position we are trying to move to
  74.         VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end );
  75.  
  76.         // see if we can make it there
  77.         pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask);
  78.  
  79.         if (trace.allsolid) {
  80.             // entity is completely trapped in another solid
  81.             pm->ps->velocity[2] = 0;    // don't build up falling damage, but allow sideways acceleration
  82.             return qtrue;
  83.         }
  84.  
  85.         if (trace.fraction > 0) {
  86.             // actually covered some distance
  87.             VectorCopy (trace.endpos, pm->ps->origin);
  88.         }
  89.  
  90.         if (trace.fraction == 1) {
  91.              break;        // moved the entire distance
  92.         }
  93.  
  94.         // save entity for contact
  95.         PM_AddTouchEnt( trace.entityNum );
  96.  
  97.         time_left -= time_left * trace.fraction;
  98.  
  99.         if (numplanes >= MAX_CLIP_PLANES) {
  100.             // this shouldn't really happen
  101.             VectorClear( pm->ps->velocity );
  102.             return qtrue;
  103.         }
  104.  
  105.         //
  106.         // if this is the same plane we hit before, nudge velocity
  107.         // out along it, which fixes some epsilon issues with
  108.         // non-axial planes
  109.         //
  110.         for ( i = 0 ; i < numplanes ; i++ ) {
  111.             if ( DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) {
  112.                 VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity );
  113.                 break;
  114.             }
  115.         }
  116.         if ( i < numplanes ) {
  117.             continue;
  118.         }
  119.         VectorCopy (trace.plane.normal, planes[numplanes]);
  120.         numplanes++;
  121.  
  122.         //
  123.         // modify velocity so it parallels all of the clip planes
  124.         //
  125.  
  126.         // find a plane that it enters
  127.         for ( i = 0 ; i < numplanes ; i++ ) {
  128.             into = DotProduct( pm->ps->velocity, planes[i] );
  129.             if ( into >= 0.1 ) {
  130.                 continue;        // move doesn't interact with the plane
  131.             }
  132.  
  133.             // see how hard we are hitting things
  134.             if ( -into > pml.impactSpeed ) {
  135.                 pml.impactSpeed = -into;
  136.             }
  137.  
  138.             // slide along the plane
  139.             PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP );
  140.  
  141.             // slide along the plane
  142.             PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP );
  143.  
  144.             // see if there is a second plane that the new move enters
  145.             for ( j = 0 ; j < numplanes ; j++ ) {
  146.                 if ( j == i ) {
  147.                     continue;
  148.                 }
  149.                 if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) {
  150.                     continue;        // move doesn't interact with the plane
  151.                 }
  152.  
  153.                 // try clipping the move to the plane
  154.                 PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP );
  155.                 PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP );
  156.  
  157.                 // see if it goes back into the first clip plane
  158.                 if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) {
  159.                     continue;
  160.                 }
  161.  
  162.                 // slide the original velocity along the crease
  163.                 CrossProduct (planes[i], planes[j], dir);
  164.                 VectorNormalize( dir );
  165.                 d = DotProduct( dir, pm->ps->velocity );
  166.                 VectorScale( dir, d, clipVelocity );
  167.  
  168.                 CrossProduct (planes[i], planes[j], dir);
  169.                 VectorNormalize( dir );
  170.                 d = DotProduct( dir, endVelocity );
  171.                 VectorScale( dir, d, endClipVelocity );
  172.  
  173.                 // see if there is a third plane the the new move enters
  174.                 for ( k = 0 ; k < numplanes ; k++ ) {
  175.                     if ( k == i || k == j ) {
  176.                         continue;
  177.                     }
  178.                     if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) {
  179.                         continue;        // move doesn't interact with the plane
  180.                     }
  181.  
  182.                     // stop dead at a tripple plane interaction
  183.                     VectorClear( pm->ps->velocity );
  184.                     return qtrue;
  185.                 }
  186.             }
  187.  
  188.             // if we have fixed all interactions, try another move
  189.             VectorCopy( clipVelocity, pm->ps->velocity );
  190.             VectorCopy( endClipVelocity, endVelocity );
  191.             break;
  192.         }
  193.     }
  194.  
  195.     if ( gravity ) {
  196.         VectorCopy( endVelocity, pm->ps->velocity );
  197.     }
  198.  
  199.     // don't change velocity if in a timer (FIXME: is this correct?)
  200.     if ( pm->ps->pm_time ) {
  201.         VectorCopy( primal_velocity, pm->ps->velocity );
  202.     }
  203.  
  204.     return ( bumpcount != 0 );
  205. }
  206.  
  207. /*
  208. ==================
  209. PM_StepSlideMove
  210.  
  211. ==================
  212. */
  213. void PM_StepSlideMove( qboolean gravity ) {
  214.     vec3_t        start_o, start_v;
  215.     vec3_t        down_o, down_v;
  216.     trace_t        trace;
  217. //    float        down_dist, up_dist;
  218. //    vec3_t        delta, delta2;
  219.     vec3_t        up, down;
  220.  
  221.     VectorCopy (pm->ps->origin, start_o);
  222.     VectorCopy (pm->ps->velocity, start_v);
  223.  
  224.     if ( PM_SlideMove( gravity ) == 0 ) {
  225.         return;        // we got exactly where we wanted to go first try    
  226.     }
  227.  
  228.     VectorCopy(start_o, down);
  229.     down[2] -= STEPSIZE;
  230.     pm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);
  231.     VectorSet(up, 0, 0, 1);
  232.     // never step up when you still have up velocity
  233.     if ( pm->ps->velocity[2] > 0 && (trace.fraction == 1.0 ||
  234.                                         DotProduct(trace.plane.normal, up) < 0.7)) {
  235.         return;
  236.     }
  237.  
  238.     VectorCopy (pm->ps->origin, down_o);
  239.     VectorCopy (pm->ps->velocity, down_v);
  240.  
  241.     VectorCopy (start_o, up);
  242.     up[2] += STEPSIZE;
  243.  
  244.     // test the player position if they were a stepheight higher
  245.     pm->trace (&trace, up, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask);
  246.     if ( trace.allsolid ) {
  247.         if ( pm->debugLevel ) {
  248.             Com_Printf("%i:bend can't step\n", c_pmove);
  249.         }
  250.         return;        // can't step up
  251.     }
  252.  
  253.     // try slidemove from this position
  254.     VectorCopy (up, pm->ps->origin);
  255.     VectorCopy (start_v, pm->ps->velocity);
  256.  
  257.     PM_SlideMove( gravity );
  258.  
  259.     // push down the final amount
  260.     VectorCopy (pm->ps->origin, down);
  261.     down[2] -= STEPSIZE;
  262.     pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);
  263.     if ( !trace.allsolid ) {
  264.         VectorCopy (trace.endpos, pm->ps->origin);
  265.     }
  266.     if ( trace.fraction < 1.0 ) {
  267.         PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
  268.     }
  269.  
  270. #if 0
  271.     // if the down trace can trace back to the original position directly, don't step
  272.     pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, start_o, pm->ps->clientNum, pm->tracemask);
  273.     if ( trace.fraction == 1.0 ) {
  274.         // use the original move
  275.         VectorCopy (down_o, pm->ps->origin);
  276.         VectorCopy (down_v, pm->ps->velocity);
  277.         if ( pm->debugLevel ) {
  278.             Com_Printf("%i:bend\n", c_pmove);
  279.         }
  280.     } else 
  281. #endif
  282.     {
  283.         // use the step move
  284.         float    delta;
  285.  
  286.         delta = pm->ps->origin[2] - start_o[2];
  287.         if ( delta > 2 ) {
  288.             if ( delta < 7 ) {
  289.                 PM_AddEvent( EV_STEP_4 );
  290.             } else if ( delta < 11 ) {
  291.                 PM_AddEvent( EV_STEP_8 );
  292.             } else if ( delta < 15 ) {
  293.                 PM_AddEvent( EV_STEP_12 );
  294.             } else {
  295.                 PM_AddEvent( EV_STEP_16 );
  296.             }
  297.         }
  298.         if ( pm->debugLevel ) {
  299.             Com_Printf("%i:stepped\n", c_pmove);
  300.         }
  301.     }
  302. }
  303.  
  304.